package com.ruoyi.comment.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.comment.mapper.CommentContentMapper;
import com.ruoyi.comment.service.ICommentService;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.model.auth.AuthContextHolder;
import com.ruoyi.model.comment.Comment;
import com.ruoyi.model.comment.dto.CommentDto;
import com.ruoyi.model.comment.params.CommentCategoryParams;
import com.ruoyi.model.comment.params.CommentParams;
import com.ruoyi.model.comment.vo.ActivitySVo;
import com.ruoyi.model.contest.Contest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author : 张怀秋
 **/
@Service
public class CommentServiceImpl extends ServiceImpl<CommentContentMapper, Comment> implements ICommentService {

    /**
     * redis缓存服务
     */
    @Resource
    private RedisCache redisCache;

    @Resource
    private CommentContentMapper commentContentMapper;

    /**
     * 发布评论
     *
     * @param commentDto 发布评论的内容
     * @return 发布是否成功
     */
    @Override
    @Transactional
    public boolean sendCommentContent(CommentDto commentDto) {
        // 获取评论的根评论id
        String rootId = commentDto.getRootId();
        // 获取回复的评论的id
        String toCommentId = commentDto.getToCommentId();
        // 获取回复的用户的
        String toCommentUserId = commentDto.getToCommentUserId();

        //如果回复的评论id是空那么默认它为根评论直接保存即可
        if (StringUtils.isEmpty(toCommentId) && StringUtils.isEmpty(toCommentUserId)) {
            Comment comment = BeanCopyUtils.copyBean(commentDto, Comment.class);
            comment.setRootId("0");
            comment.setUserId(AuthContextHolder.getUserId());
            comment.setUserName(AuthContextHolder.getUserInfo().getName());
            comment.setToCommentUserId("0");
            comment.setToCommentId("0");
            comment.setPushTime(new Date());
            redisCache.deleteObject(commentDto.getTypeName() + ":" + commentDto.getActivityId());
            this.baseMapper.insert(comment);
            return true;
        }

        //如果回复评论id不是空那么说明该评论类型是回复
        if (StringUtils.isNotEmpty(toCommentId) && StringUtils.isNotEmpty(toCommentUserId)) {
            Comment comment = BeanCopyUtils.copyBean(commentDto, Comment.class);
            comment.setUserId(AuthContextHolder.getUserId());
            comment.setUserName(AuthContextHolder.getUserInfo().getName());
            comment.setRootId(rootId);
            comment.setToCommentUserId(toCommentUserId);
            comment.setPushTime(new Date());

            //直接去查询redis中zset的相关值 直接删除它
            redisCache.deleteObject(commentDto.getTypeName() + ":" + commentDto.getActivityId());

            //然后往子评论列表中加入这次的新评论
            this.baseMapper.insert(comment);
            return true;
        }
        throw new RuntimeException("数据可能发生异常");
    }

    /**
     * 查询某某详情的评论列表
     *
     * @param commentParams 类型以及详情id
     * @param page          当前页码
     * @param limit         每页记录数量
     * @return AjaxResult
     */
    @Override
//    @Cacheable(value = "commentList", key = "#commentParams.typeName + ':' + #commentParams.activityId")
    public AjaxResult queryDetailComment(CommentParams commentParams, Long page, Long limit) {
        //1.查询如何是否命中缓存
        Set<Object> result = redisCache.rangeZset(commentParams.getTypeName() + ":" + commentParams.getActivityId(),
                (page - 1) * limit, (page - 1) * limit + limit - 1);
        if (CollectionUtils.isNotEmpty(result)) {
            //命中缓存直接返回数据
            System.out.println("这一次访问已经命中缓存");
            return AjaxResult.success(result);
        }
        System.out.println("这一次访问没有命中缓存");
        //2.先查询一次将所有数据存入redis 存zSet
        List<Comment> comments = this.baseMapper.selectList(Wrappers.<Comment>lambdaQuery()
                .eq(Comment::getActivityId, commentParams.getActivityId())
                .eq(Comment::getType, commentParams.getType()));

        //根据id进行分组
        Map<String, List<Comment>> fIdCommentMap = comments.stream().collect(Collectors.groupingBy(Comment::getId));
        //遍历这个集合将其数据完善
        comments.forEach(item -> {
            if (CollectionUtils.isNotEmpty(fIdCommentMap.get(item.getToCommentId()))) {
                Comment comment = fIdCommentMap.get(item.getToCommentId()).get(0);
                item.setToCommentName(comment.getUserName());
            }
        });

        //获取到当前评论按照根评论进行分组
        Map<String, List<Comment>> listMap = comments.stream().collect(Collectors.groupingBy(Comment::getRootId));
        //然后用stream进行组装
        List<Comment> treeCommentList = listMap.get("0").stream().map(item ->
                item.setChildren(listMap.get(item.getId()))
        ).collect(Collectors.toList()); //封装好的数据

        //3.第一次访问接口 根据limit取出展示的数据
        List<Comment> limitCommentList = treeCommentList.stream().limit(limit).collect(Collectors.toList());

        //4.正式开始存入redis
        treeCommentList.forEach((item -> {
            long time = item.getPushTime().getTime();//时间戳作为“分数”
            redisCache.addZset(commentParams.getTypeName() + ":" + commentParams.getActivityId(), item, time);
        }));

        return AjaxResult.success(limitCommentList);
    }

    /**
     * 根据分类查询展示对应列表，带分页
     *
     * @param categoryParams 参数类型
     * @return list<ActivitySVo>
     */
    @Override
    public List<ActivitySVo> findAllAtivitysByCategoryId(CommentCategoryParams categoryParams) {

        //将这个父分类带入Mapper进行查询，如果，查询所有的子类
        Assert.isTrue(StringUtils.isNotEmpty(categoryParams.getCategoryId()), "请选择分类id");
        List<String> childCIdList = this.commentContentMapper.selectCategoryChildByCId(categoryParams.getCategoryId());
        if (CollectionUtils.isNotEmpty(childCIdList)) {
            //进入这个地方，说明是竞赛，由于目前竞赛是三级分类，在9月22日，修改这段逻辑
            List<ActivitySVo> activitySVos = new ArrayList<>();
            childCIdList.forEach(item -> {
                List<ActivitySVo> activitySVoList = this.commentContentMapper.selectAllAtivityByCategoryId(item);
                activitySVos.addAll(activitySVoList);
            });
            return activitySVos;
        } else {
            return this.commentContentMapper.selectAllAtivityByCategoryId(categoryParams.getCategoryId());
        }

    }

    /**
     * 后台：根据详情查询评论列表
     *
     * @param page     当前页码
     * @param limit    每页记录数
     * @param type     区分详情类型
     * @param detailId 详情id
     * @return 评论列表
     */
    @Override
    public Map<String, Object> selectCommentListByDetailId(Long page, Long limit, String type, String detailId, Comment comment) {
        Map<String, Object> map = new HashMap<>();
        Page<Comment> commentPage = this.baseMapper.selectPage(new Page<>(page, limit),
                Wrappers.<Comment>lambdaQuery()
                        .eq(StringUtils.isNotEmpty(comment.getUserName()), Comment::getUserName, comment.getUserName())
                        .like(StringUtils.isNotEmpty(comment.getContent()), Comment::getContent, comment.getContent())
                        .eq((StringUtils.isEmpty(comment.getUserName()) && StringUtils.isEmpty(comment.getContent())), Comment::getRootId, "0")
                        .eq(Comment::getActivityId, detailId));
        List<Comment> records = commentPage.getRecords();
        if (CollectionUtils.isNotEmpty(records)) {
            //赋值子集合
            records.forEach(item -> {
                List<Comment> comments = this.baseMapper.selectList(Wrappers.<Comment>lambdaQuery().eq(Comment::getToCommentId, item.getId()));
                item.setChildren(comments);
            });
        }
        map.put("rows", records);
        map.put("total", commentPage.getTotal());
        return map;
    }


}
